<template>
  <div class="pixi">
    <div class="coll">
      <el-button @click="handleSave">导出</el-button>
      <div>
        <label for="">自动校色</label>
        <el-switch
          v-model="auto"
          :active-value="true"
          :inactive-value="false"
          @change="handleAutoChange"
        />
      </div>
      <div>
        <label for="">曝光度</label>
        <el-slider
          v-model="expousreVal"
          :min="-100"
          :max="100"
          @input="handleExpousreChange"
          size="small"
        />
      </div>
      <div>
        <label for="">亮度</label>
        <el-slider
          :min="-150"
          :max="150"
          v-model="brightnessVal"
          @input="handleBrightnessChange"
        ></el-slider>
      </div>
      <div>
        <label for="">对比度</label>
        <el-slider
          :min="-100"
          :max="100"
          v-model="contrastVal"
          @input="handleContrastChange"
        ></el-slider>
      </div>
      <div>
        <label for="">高光</label>
        <el-slider
          :min="-100"
          :max="100"
          v-model="highlightVal"
          @input="handleHighlightChange"
        ></el-slider>
      </div>
      <div>
        <label for="">阴影</label>
        <el-slider
          :min="-100"
          :max="100"
          v-model="shadowVal"
          @input="handleShadowChange"
        ></el-slider>
      </div>
      <div>
        <label for="">色相</label>
        <el-slider
          :min="-180"
          :max="180"
          v-model="hueVal"
          @input="handleHueChange"
        ></el-slider>
      </div>
      <div>
        <label for="">饱和度</label>
        <el-slider
          :min="-100"
          :max="100"
          v-model="saturateVal"
          @input="handleSaturateChange"
        ></el-slider>
      </div>
    </div>
    <div class="container" ref="containerRef"></div>
  </div>
</template>

<script setup lang="ts">
import download from 'downloadjs'
import { ElMessage } from 'element-plus'
import {
  Application,
  Assets,
  Filter,
  GlProgram,
  Renderer,
  Sprite,
} from 'pixi.js'
import { onMounted, ref } from 'vue'

// import testImage from '@/assets/111.jpeg'
// import testImage from '@/assets/222.jpg'
import testImage from '@/assets/333.png'

import fragment from './pixi/fragment'
import { getImageData } from './pixi/utils'
import vertex from './pixi/vertex'

const myFilter = new Filter({
  glProgram: new GlProgram({
    fragment,
    vertex,
  }),
  resources: {
    timeUniforms: {
      gainRGB: {
        type: 'vec3<f32>',
        value: [0, 0, 0],
      },
      auto: { value: 0, type: 'i32' }, // 0: false, 1: true
      expousre: { value: 0, type: 'f32' },
      brightness: { value: 0.0, type: 'f32' },
      contrast: { value: 0.0, type: 'f32' },
      highlight: { value: 0.0, type: 'f32' },
      shadow: { value: 0.0, type: 'f32' },
      hue: { value: 0.0, type: 'f32' },
      saturate: { value: 0.0, type: 'f32' },
      width: { value: 0, type: 'i32' },
      height: { value: 0, type: 'i32' },
    },
  },
})

const containerRef = ref<HTMLDivElement>()

let app: Application<Renderer> | null = null
let background: Sprite | null = null

const auto = ref<boolean>(false)
const expousreVal = ref(0)
const brightnessVal = ref(0)
const contrastVal = ref(0)
const highlightVal = ref(0)
const shadowVal = ref(0)
const hueVal = ref(0)
const saturateVal = ref(0)
const handleExpousreChange = () => {
  myFilter.resources.timeUniforms.uniforms.expousre = expousreVal.value
}
const handleBrightnessChange = () => {
  myFilter.resources.timeUniforms.uniforms.brightness = brightnessVal.value
}
const handleContrastChange = () => {
  myFilter.resources.timeUniforms.uniforms.contrast = contrastVal.value
}
const handleHighlightChange = () => {
  myFilter.resources.timeUniforms.uniforms.highlight = highlightVal.value
}
const handleShadowChange = () => {
  myFilter.resources.timeUniforms.uniforms.shadow = shadowVal.value
}
const handleHueChange = () => {
  myFilter.resources.timeUniforms.uniforms.hue = hueVal.value
}
const handleSaturateChange = () => {
  myFilter.resources.timeUniforms.uniforms.saturate = saturateVal.value
}

const handleAutoChange = (value: boolean | string | number) => {
  myFilter.resources.timeUniforms.uniforms.auto = value ? 1 : 0
}

const scale = ref(1)

// 0-255的6次方查找表
const tablePow6 = [
  0, 1, 64, 729, 4096, 15625, 46656, 117649, 262144, 531441, 1000000, 1771561,
  2985984, 4826809, 7529536, 11390625, 16777216, 24137569, 34012224, 47045881,
  64000000, 85766121, 113379904, 148035889, 191102976, 244140625, 308915776,
  387420489, 481890304, 594823321, 729000000, 887503681, 1073741824, 1291467969,
  1544804416, 1838265625, 2176782336, 2565726409, 3010936384, 3518743761,
  4096000000, 4750104241, 5489031744, 6321363049, 7256313856, 8303765625,
  9474296896, 10779215329, 12230590464, 13841287201, 15625000000, 17596287801,
  19770609664, 22164361129, 24794911296, 27680640625, 30840979456, 34296447249,
  38068692544, 42180533641, 46656000000, 51520374361, 56800235584, 62523502209,
  68719476736, 75418890625, 82653950016, 90458382169, 98867482624, 107918163081,
  117649000000, 128100283921, 139314069504, 151334226289, 164206490176,
  177978515625, 192699928576, 208422380089, 225199600704, 243087455521,
  262144000000, 282429536481, 304006671424, 326940373369, 351298031616,
  377149515625, 404567235136, 433626201009, 464404086784, 496981290961,
  531441000000, 567869252041, 606355001344, 646990183449, 689869781056,
  735091890625, 782757789696, 832972004929, 885842380864, 941480149401,
  1000000000000, 1061520150601, 1126162419264, 1194052296529, 1265319018496,
  1340095640625, 1418519112256, 1500730351849, 1586874322944, 1677100110841,
  1771561000000, 1870414552161, 1973822685184, 2081951752609, 2194972623936,
  2313060765625, 2436396322816, 2565164201769, 2699554153024, 2839760855281,
  2985984000000, 3138428376721, 3297303959104, 3462825991689, 3635215077376,
  3814697265625, 4001504141376, 4195872914689, 4398046511104, 4608273662721,
  4826809000000, 5053913144281, 5289852801024, 5534900853769, 5789336458816,
  6053445140625, 6327518887936, 6611856250609, 6906762437184, 7212549413161,
  7529536000000, 7858047974841, 8198418170944, 8550986578849, 8916100448256,
  9294114390625, 9685390482496, 10090298369529, 10509215371264, 10942526586601,
  11390625000000, 11853911588401, 12332795428864, 12827693806929,
  13339032325696, 13867245015625, 14412774445056, 14976071831449,
  15557597153344, 16157819263041, 16777216000000, 17416274304961,
  18075490334784, 18755369578009, 19456426971136, 20179187015625,
  20924183895616, 21691961596369, 22483074023424, 23298085122481,
  24137569000000, 25002110044521, 25892303048704, 26808753332089,
  27752076864576, 28722900390625, 29721861554176, 30749609024289,
  31806802621504, 32894113444921, 34012224000000, 35161828327081,
  36343632130624, 37558352909169, 38806720086016, 40089475140625,
  41407371740736, 42761175875209, 44151665987584, 45579633110361,
  47045881000000, 48551226272641, 50096498540544, 51682540549249,
  53310208315456, 54980371265625, 56693912375296, 58451728309129,
  60254729561664, 62103840598801, 64000000000000, 65944160601201,
  67937289638464, 69980368892329, 72074394832896, 74220378765625,
  76419346977856, 78672340886049, 80980417183744, 83344647990241,
  85766121000000, 88245939632761, 90785223184384, 93385106978409,
  96046742518336, 98771297640625, 101559956668416, 104413920565969,
  107334407093824, 110322650964681, 113379904000000, 116507435287321,
  119706531338304, 122978496247489, 126324651851776, 129746337890625,
  133244912166976, 136821750708889, 140478247931904, 144215816802121,
  148035889000000, 151939915084881, 155929364660224, 160005726539569,
  164170508913216, 168425239515625, 172771465793536, 177210755074809,
  181744694737984, 186374892382561, 191102976000000, 195930594145441,
  200859416110144, 205891132094649, 211027453382656, 216270112515625,
  221620863468096, 227081481823729, 232653764952064, 238339532186001,
  244140625000000, 250058907189001, 256096265048064, 262254607552729,
  268535866540096, 274941996890625,
]
onMounted(async () => {
  // Load the grass texture
  const grassTexture = await Assets.load(testImage)
  background = new Sprite(grassTexture)
  // The application will create a renderer using WebGL, if possible,
  // with a fallback to a canvas render. It will also setup the ticker
  // and the root stage PIXI.Container
  app = new Application()

  // Wait for the Renderer to be available
  await app.init({
    background: '0xffffff',
    width: background.width,
    height: background.height,
    // resizeTo: containerRef.value,
    preference: 'webgl',
  })

  containerRef.value?.appendChild(app.canvas)
  const imageData = getImageData(grassTexture.source.resource)
  if (!imageData) return
  const sumRGB = [0, 0, 0]
  for (let i = 0; i < imageData.length; i += 4) {
    sumRGB[0] += tablePow6[imageData[i]]
    sumRGB[1] += tablePow6[imageData[i + 1]]
    sumRGB[2] += tablePow6[imageData[i + 2]]
  }
  // 开6次根号
  sumRGB[0] = Math.pow(sumRGB[0], 1.0 / 6)
  sumRGB[1] = Math.pow(sumRGB[1], 1.0 / 6)
  sumRGB[2] = Math.pow(sumRGB[2], 1.0 / 6)
  // 求均值
  const avgRGB = Math.sqrt(
    (sumRGB[0] * sumRGB[0] + sumRGB[1] * sumRGB[1] + sumRGB[2] * sumRGB[2]) /
      3.0,
  )
  // 求增益
  const gainRGB = [0, 0, 0]
  gainRGB[0] = avgRGB / sumRGB[0]
  gainRGB[1] = avgRGB / sumRGB[1]
  gainRGB[2] = avgRGB / sumRGB[2]
  myFilter.resources.timeUniforms.uniforms.gainRGB = gainRGB
  console.log(myFilter)
  // Create the grass background
  myFilter.resources.timeUniforms.uniforms.width = background.width
  myFilter.resources.timeUniforms.uniforms.height = background.height
  // background.texture.
  scale.value = Math.min(
    containerRef.value?.clientWidth! / background.width,
    containerRef.value?.clientHeight! / background.height,
  )
  app.stage.scale.set(scale.value)
  // background.scale.set(scale)
  app.stage.addChild(background)
  background.filters = [myFilter]
})

const handleSave = async () => {
  if (!background) return ElMessage.warning('背景图不存在')
  const base64 = await app?.renderer.extract.base64({
    target: background,
    format: 'png',
  })
  download(base64, 'pixi.png')
}
</script>

<style scoped lang="scss">
.pixi {
  width: 100%;
  height: calc(100vh - 60px - 50px - 40px);
  display: flex;
  .coll {
    width: 300px;
    flex-shrink: 0;
    margin-right: 20px;
  }
  // .container {
  // flex: 1;
  // height: 10000px;
  // }
}
</style>
